﻿using Newtonsoft.Json;
using NLog;
using OrBitDataModule.Adaptor;
using OrBitDataModule.Base;
using OrBitDataModule.Common;
using OrBitDataModule.Contract;
using OrBitDataModule.CustomEventHandler;
using OrBitDataModule.Interface;
using OrBitDataModule.Models;
using Quartz;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace OrBitDataModule.Protocol
{
    [ProtocolType("Socket客户端")]
    public class SocketClientProvider : DataTaskBase
    {
        public SocketClientProvider(string uniqueId, string dataProtocolScriptId, string configJson, string taskName, string taskProtocolType, string apiName, string username, string password)
        {

            this.UniqueId = uniqueId;
            this.TaskName = taskName;
            this.TaskProtocolType = taskProtocolType;
            this.UserName = username;
            this.Password = password;
            this.ApiName = apiName;
            this.ConfigJson = configJson;
            this.DataProtocolScriptId = dataProtocolScriptId;
        }
        ~SocketClientProvider()
        {

            this.OnDispose();
        }
        public override IContext Context { get; set; }
        public override string ConfigJson { get; }
        public override string UniqueId { get; }
        public override string DataProtocolScriptId { get; }
        public override string TaskName { get; }
        public override string UserName { get; }
        public override string Password { get; }
        public override string ApiName { get; }
        public override string Token { get; set; }
        public override int Expiration { get; set; } = 0;
        public override bool IsScripDebug { get; set; } = false;
        public override string ScriptName { get; set; }
        public override string ScriptCode { get; set; }
        public override ScriptRunner ScripterRunner { get; set; }
        public override ScriptBase Script { set; get; }
        public override Encoding DefaultEncoding => StringUtils.GetEncoding(socketClient.DefaultEncoding);
        public override string TaskProtocolType { get; }
        public override SerialPort SerialPortInstance { get; set; }
        public override SocketTcpClient TcpClientInstance { get; set; }

        private SocketClient socketClient = null;

        public override event EventHandler<TaskEventArgs> OnStateChange;

        /// <summary>
        /// 是否拦截接收
        /// </summary>
        private bool IsReceiveIntercepted = false;
        /// <summary>
        /// 最后一条消息
        /// </summary>
        private string lastMessage = string.Empty;

        public override void OnLoad()
        {
            try
            {
                this.ScripterRunner = new ScriptRunner();
                socketClient = Newtonsoft.Json.JsonConvert.DeserializeObject<SocketClient>(ConfigJson);
                this.SettingProperty = new SettingDictionary(socketClient);
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
            }
        }

        public override async void Start()
        {
            try
            {
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Starting));

                if (!string.IsNullOrWhiteSpace(this.DataProtocolScriptId))
                {
                    var result = await ScriptApi.GetCodeAsync(this.DataProtocolScriptId);
                    this.ScriptName = result.ScriptName;
                    this.ScriptCode = result.ScriptCode;

                    CompileScript();
                    if (!this.CanRunScript)
                    {
                        OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
                        return;
                    }
                }
                Script?.OnLoad();

                this.TcpClientInstance = new SocketTcpClient(socketClient.MachineNo, socketClient.Networkinterface, socketClient.IP, socketClient.Port, DefaultEncoding);

                TcpClientInstance.OnConnected += TcpClient_OnConnected;
                TcpClientInstance.OnDisconnected += TcpClient_OnDisconnected;
                TcpClientInstance.OnDataReceived += TcpClient_OnDataReceived;
                TcpClientInstance.Connect();
                WriteLog($"已启动!");
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Started));
                Script?.OnStarted();
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
                OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
            }
        }

        private async void TcpClient_OnDataReceived(object sender, ReceivedDataEventArgs e)
        {
            try
            {
                Script?.SocketClient_OnDataReceived(sender, e);
                //处理消息拦截，还是要在脚本处理之后再拦截
                if (this.IsReceiveIntercepted)
                {
                    this.lastMessage = DefaultEncoding.GetString(e.Buffer);
                    IsReceiveIntercepted = false;
                    return;
                }

                if (string.IsNullOrWhiteSpace(Token))
                {
                    GetWebApiToken();
                    if (string.IsNullOrWhiteSpace(Token))
                    {
                        WriteLog("接口未能获取到token，请检查", LogLevel.Error);
                        return;
                    }
                }
                string text = DefaultEncoding.GetString(e.Buffer);

                InputParameter inputParameter = new InputParameter()
                {
                    TaskName = TaskName,
                    ApiName = ApiName,
                    UserName = UserName,
                    ProtocolType = "Socket客户端",
                    ClientIP = e.IP,
                    ClientMAC = NetworkUtils.GetLocalMACAddress(),
                    ClientHostName = NetworkUtils.GetComputerName(),
                    MachineNo = e.MachineNo,
                    Parameter1 = JsonConvert.SerializeObject(LocalSetting.GetConfig(this.UniqueId).parameters),
                    Parameter2 = e.IP,
                    Parameter3 = e.Port.ToString()
                };
                Script?.BeforeSubmit(inputParameter, text);
                var result = await WebApi.IntegrationApiPostAsync(ApiName, Token, inputParameter, text);
                if (e.IsSend)
                {
                    // 接口如果返回空字符串就不发送给socket服务
                    if (!string.IsNullOrWhiteSpace(result.OutputResponse))
                    {
                        e.Send(result.OutputResponse);
                    }
                }

                WriteLog($"Socket客户端：{e.IP}:{e.Port}，已提交至接口：{ApiName},返回:{result.Result},信息:{result.ReturnMessage}", LogLevel.Info);
                Script?.AfterSubmit(result.Result, result.ReturnMessage, result.ReturnMessage);
                //inputParameter = null;
                //e = null;
                //GC.Collect();
            }
            catch (Exception ex)
            {
                Script?.OnError(ex);
                WriteLog(ex.Message);
            }
        }

        private void TcpClient_OnDisconnected(object sender, SockeClientEventArgs e)
        {
            WriteLog($"设备编码：{e.MachineNo},IP:{e.IP}:{e.Port} ,断开连接");
        }

        private void TcpClient_OnConnected(object sender, SockeClientEventArgs e)
        {
            WriteLog($"设备编码：{e.MachineNo},IP:{e.IP}:{e.Port} ,连接成功");
        }
        public override string SendExternal(string message)
        {
            this.IsReceiveIntercepted = true;
            this.lastMessage = string.Empty;
            this.TcpClientInstance.Send(DefaultEncoding.GetBytes(message));
            int times = 150;

            while (IsReceiveIntercepted)
            {
                if (times == 0)
                {
                    break;
                }
                Thread.Sleep(50);
                times--;
            }
            return lastMessage;
        }
        public override void Stop()
        {
            OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stopping));
            TcpClientInstance.DisConnect();
            WriteLog("已停止");
            OnStateChange?.Invoke(this, new TaskEventArgs(this.UniqueId, TaskRunningStatus.Stoped));
        }
        public override void OnDispose()
        {
            this.TcpClientInstance.DisConnect();
            this.TcpClientInstance.Dispose();
        }
    }
}
